package strategy

import (
	"context"
	"encoding/json"
	"json"

	ctpdefine "gitee.com/boxigg/ctpdefine"
	ctpredis "gitee.com/boxigg/ctpredis"

	"github.com/sirupsen/logrus"
)

type StraBase struct {
	Name         string //strategy class name
	StraID       string // strategy instance id
	InstrumentID string
	Variables    map[string]any //
	Params       map[string]Param
	Interval     IntervalType

	tick         TickData
	ticks        []TickData
	bar          BarData
	bars         []BarData
	
	OnTick       StraOnTickType
	OnTicks      StraOnTicksType
	OnBar        StraOnBarType
	OnBars       StraOnBarsType
	

	modeType ModeType
	periods  int //

	rdb *ctpredis.StraRedis
}

// 策略通用接口
type IStra interface {

	//每个策略要实现下面四个方法的1、2或者3、4或者1、3、4或者1、2、3、4
	//1. StraOnTickType ：当策略基于tick数据时，调用
	StraOnTick(tick ctpdefine.StraTickField)

	//2. StraOnTicksType ：当策略初始化或者回测时调用
	StraOnTicks(ticks []ctpdefine.StraTickField)

	//3. StraOnBarType :当策略基于Bar数据时，调用
	StraOnBar(bar ctpdefine.BarField)

	//4. StraOnBarsType :当策略初始化或者回测时调用
	StraOnBars(bars []ctpdefine.BarField)
	//5. 当策略有新的信号产生时调用
	StraOnSignal(signal StraSignal)

	//6. Start()
	Start()

	//7. InitStra(params )
	InitStra(params map[string]any)

	Stop()
}
type InitStraType func()

// 每个策略要实现下面四个方法的1、2或者3、4或者1、3、4或者1、2、3、4
// 1. StraOnTickType ：当策略基于tick数据时，调用
type StraOnTickType func(tick TickData)

// 2. StraOnTicksType ：当策略初始化或者回测时调用
type StraOnTicksType func(ticks []TickData)

// 3. StraOnBarType :当策略基于Bar数据时，调用
type StraOnBarType func(bar BarData)

// 4. StraOnBarsType :当策略初始化或者回测时调用
type StraOnBarsType func(bars []BarData)

func NewStra(instrument string, mode ModeType, 
	params map[string]Param, rdb *ctpredis.StraRedis) *StraBase {
	stra := new(StraBase)
	stra.InstrumentID = instrument
	stra.modeType = mode
	stra.Params = params

	stra.rdb = rdb

	return stra
}
func (stra *StraBase) Init(instrument string, mode ModeType, rdb *ctpredis.StraRedis,
	params map[string]Param, periods int) {

	stra.InstrumentID = instrument
	stra.modeType = mode
	stra.rdb = rdb
	stra.periods = periods
	stra.Params = params

}
func (stra *StraBase) OnInit() {
	stra.rdb.Publish(ctpredis.REQSUBINST, stra.InstrumentID)
}
func (s *StraBase) Start() {
	ctx := context.Background()
	sub := s.rdb.Rdb.Subscribe(ctx, s.InstrumentID)
	ch := make(chan int)
	go func() {
		defer sub.Close()
		msg := sub.Channel()
		for {
			select {
			case <-ch:
				logrus.Info("Return from strategy.straBase.go.Start")
			case data := <-msg:
				if data == nil {
					logrus.Info("No msg from strategy.straBase.sub")
					break
				}
			}
		}
	}()
	ch <- 1
}

// 当策略产生信号时调用
func (s *StraBase) OnStraSignal(ss StraSignal) {
	// sof,_:=o.(ctpdefine.StrategyOrderField)
	js, _ := json.Marshal(ss)
	s.rdb.PublishStraSignal(s.Id, js)
}

func StartStra(stra *StraBase) {

}
